package vn.allmobile.happyvoucher.loader;

import java.util.ArrayList;
import java.util.List;

import org.json.JSONException;
import org.json.JSONObject;

import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
import android.support.v4.content.Loader;
import android.util.Log;
 
public abstract class BaseLoader extends Loader<BaseResult>
{
    private static final String TAG = "BaseLoader";
    
    protected String mEtag;
    private boolean mHasDeliverdResult = false;
    protected volatile boolean mIsLoading = false;
    protected boolean mNeedDatabase = true;
    protected boolean mNeedDeliverResult = true;
    protected boolean mNeedServer = true;
    private int mNextExecuteTask = 0;
    private ProgressNotifiable mProgressNotifiable;
    protected BaseResult mResult;
    private List<AsyncTask<Void, Void, BaseResult>> mTaskList = new ArrayList<AsyncTask<Void,Void,BaseResult>>();
    
    public BaseLoader(Context context)
    {
        super(context);
        this.mResult = getResultInstance();
        Log.i(TAG,"BaseLoader constructor");
    }
    
    public static void setmHasDeliverdResult(BaseLoader loader, boolean hasDeliverd)
    {
    	loader.mHasDeliverdResult =  hasDeliverd;    	
    }
    
    protected boolean dataExists()
    {
        if ((this.mResult.getCount() > 0) && (this.mHasDeliverdResult))
        	return true;
        return false;
    }
    
    protected void executeNextTask()
    {
    	Log.i(TAG,"executeNextTask");
        if (hasNextTask())
        {
            AsyncTask<Void,Void,BaseResult> localAsyncTask = null;
            
            while((localAsyncTask == null) && (hasNextTask()))
            {
                localAsyncTask = (AsyncTask<Void,Void,BaseResult>)this.mTaskList.get(this.mNextExecuteTask);
                this.mNextExecuteTask = (1 + this.mNextExecuteTask);
            }
            if (localAsyncTask != null)
            	localAsyncTask.execute(new Void[0]);
        }
    }
    
    protected abstract BaseResult getResultInstance();
    
    protected abstract UpdateTask getUpdateTask();
    
    protected BaseResult onDataLoaded(BaseResult result1, BaseResult result2)
    {
      return result2;
    }
    protected boolean hasNextTask()
    {
        if (this.mNextExecuteTask < this.mTaskList.size())
        	return true;
        return false;               
    }
    
    protected void initTaskList(List<AsyncTask<Void, Void, BaseResult>> list)
    {
        if (this.mNeedServer)
        {
            UpdateTask localUpdateTask = getUpdateTask();
            if (localUpdateTask != null)
            list.add(localUpdateTask);
        }
    }
    
    public boolean isLoading()
    {
        return this.mIsLoading;
    }
    
    protected boolean isUserRelated()
    {
        return false;
    }
    
    
    /*@Override
    public void deliverResult(BaseResult data) {
        if (isReset()) {
            // An async query came in while the loader is stopped
            return;
        }
        
        //this.mResult = data.shallowClone();
        //super.deliverResult(data);
        
    }
    */
    
    protected void onForceLoad()
    {
    	Log.i(TAG,"onForceLoad");
        this.mTaskList.clear();
        this.mNextExecuteTask = 0;
        initTaskList(this.mTaskList);
        
        executeNextTask();
    }
    
    protected void onStartLoading()
    {
    	Log.i(TAG,"onStartLoading");
        if (this.mResult.getCount() > 0)
        	deliverResult(this.mResult.shallowClone());
        if ((!this.mIsLoading) && ((this.mResult.getCount() == 0) || (takeContentChanged())))
        {
        	forceLoad();
         
        }
      
    }
    
    protected abstract BaseResult parseResult(JSONObject paramJSONObject, BaseResult result)
    throws Exception;
    
    public void reload()
    {
        if (!isLoading())
        { 
        	 this.mNeedDatabase = false;
            forceLoad();
        }
    }
    
    
    
    public void setNeedServer(boolean paramBoolean)
    {
        this.mNeedServer = paramBoolean;
    }
    
    public void setProgressNotifiable(ProgressNotifiable progressnotify)
    {
        this.mProgressNotifiable = progressnotify;
        if (this.mProgressNotifiable != null)
        	this.mProgressNotifiable.init(dataExists(), this.mIsLoading);
    }
   
    
    protected abstract class UpdateTask extends BaseLoader.BaseTask
    {
        protected UpdateTask()
        {
            super();
        }
        
        protected BaseResult doInBackground(Void[] params)
        {
        	Request request = getRequest();
        	
        	int statusCode = request.getStatus();
        	
        	Log.i(TAG,"request respone:" +request.getResponse());
        	Log.i(TAG,"request code:" + statusCode);
            BaseResult localBaseResult1 = BaseLoader.this.getResultInstance();
           
           
            BaseResult localBaseResult2 = null;
            switch (statusCode) {
				case Request.STATUS_OK:
					 
					JSONObject jsonObject;
					try {					
						jsonObject = new JSONObject(request.getResponse());
						localBaseResult1 = parseTaskResult(jsonObject);			
						localBaseResult2 = onDataLoaded(BaseLoader.this.mResult, localBaseResult1.shallowClone());						
						localBaseResult1 = localBaseResult2.shallowClone();
					} catch (JSONException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}                 
	                    
					break;
				case Request.STATUS_NETWORK_UNAVAILABLE:
					localBaseResult1.setResultStatus(BaseResult.ResultStatus.NETWROK_ERROR);
					break;					
				case Request.STATUS_SERVICE_UNAVAILABLE:
					localBaseResult1.setResultStatus(BaseResult.ResultStatus.SERVICE_ERROR);
					break;
				default:				
					localBaseResult1.setResultStatus(BaseResult.ResultStatus.DATA_ERROR);					
						
				}
            
            
            return localBaseResult1; 
			                  
        }
        
        protected abstract Request getRequest();
        protected BaseResult onDataLoaded(BaseResult oldResult, BaseResult newResult)
        {
            return newResult;
        }
    }
    
    
    
    protected abstract class BaseTask extends AsyncTask<Void, Void, BaseResult>
    {
        protected BaseTask()
        {
            
        }
        
        protected void onPostExecute(BaseResult result)
        {
        	 
            BaseLoader.this.mIsLoading = false;
            final BaseResult.ResultStatus localResultStatus = result.getResultStatus();
            
            if (localResultStatus != BaseResult.ResultStatus.OK)
            {
            	 
            	if (BaseLoader.this.mProgressNotifiable != null)
            	{
            		BaseLoader.this.mProgressNotifiable.onError(BaseLoader.this.dataExists(), localResultStatus, new Handler.Callback()
		            {
		                public boolean handleMessage(Message message)
		                {
		                    if (localResultStatus == BaseResult.ResultStatus.NETWROK_ERROR)
		                    {
		                        Intent intent = new Intent("android.settings.SETTINGS");
		                        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
		                        BaseLoader.this.getContext().startActivity(intent);
		                    }
		                    else{
		                        BaseLoader.this.reload();
		                    }
		                    return true;
		                }
		            });
            		
            	}	
            		
            }            			           
            else
            {
             
	    	 
	        	BaseLoader.this.mResult = result;   
	        	
	        	if ((BaseLoader.this.mProgressNotifiable == null) || (BaseLoader.this.hasNextTask()))
                {
            		BaseLoader.this.mNeedDeliverResult = true;
                }
	        	
	            if (BaseLoader.this.mNeedDeliverResult)
	            {
	                BaseLoader.this.deliverResult(result.shallowClone());
	                BaseLoader.setmHasDeliverdResult(BaseLoader.this, true);
	            }
	            
	            if (BaseLoader.this.mProgressNotifiable != null)
	            	BaseLoader.this.mProgressNotifiable.stopLoading(BaseLoader.this.dataExists(),BaseLoader.this.hasNextTask(),localResultStatus );
	            BaseLoader.this.executeNextTask();
        	
            }
           // BaseLoader.this.deliverResult(result.shallowClone());
            
        }
        
        protected void onPreExecute()
        {
            BaseLoader.this.mIsLoading = true;
            if (BaseLoader.this.mProgressNotifiable != null)
            	BaseLoader.this.mProgressNotifiable.startLoading(BaseLoader.this.dataExists());
        }
        
        protected BaseResult parseTaskResult(JSONObject jsonObject)
        {
            BaseResult resultObject = BaseLoader.this.getResultInstance();
            if (resultObject == null) throw new IllegalStateException("The parsed result should not be null, you must constructa result to indicate the task state");
            try{
                BaseResult result = BaseLoader.this.parseResult(jsonObject, (BaseResult)resultObject);
                resultObject = BaseLoader.this.onDataLoaded(BaseLoader.this.mResult,result );              
             }catch (Exception localException){
                ((BaseResult)resultObject).setResultStatus(BaseResult.ResultStatus.DATA_ERROR);
                localException.printStackTrace();                
            }
            return resultObject;
        }
    }
}